﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace VDataAdapter
{
    enum WorkerState
    {
        Stop,
        Waiting,
        Working,
        Finished
    };

    abstract class Worker
    {
        protected WorkerManager _manager;

        protected Thread _thread;

        protected ManualResetEvent _waitFlag;

        protected ManualResetEvent _signalFlag;

        protected WorkerState _state = WorkerState.Stop;

        public WorkerState State
        {
            get { return _state; }
        }

        public Worker(ManualResetEvent waitFlag, ManualResetEvent signalFlag)
        { 
            if(waitFlag != null)
                _waitFlag = waitFlag;

            if (signalFlag != null)
                _signalFlag = signalFlag;
        }

        public void AcceptManager(WorkerManager manager)
        {
            _manager = manager;
        }

        public void StartWork(Object data)
        {
            _thread = new Thread(StartWorkingThread);
            _thread.Start(data);            
        }

        protected void StartWorkingThread(Object data)
        {
            // wait for others' flag
            _state = WorkerState.Waiting;

            WaitForFlags();

            // report start working
            _state = WorkerState.Working;

            // take over my flag
            ResetMyFlags();

            if (_manager != null)
            {
                _manager.ReportStart(this);
            }
            
            DoWork(data);
            
            // signal other waiting threads
            SignalMyFlags();
            
            // report finished
            if (_manager != null)
            {
                _manager.ReportFinished(this);
            }
        }

        private void SignalMyFlags()
        {
            if(_signalFlag != null)                
                _signalFlag.Set();
        }

        private void ResetMyFlags()
        {
            if (_signalFlag != null)
                _signalFlag.Reset();
        }

        private void WaitForFlags()
        {
            if (_waitFlag != null)
                _waitFlag.WaitOne();
        }

        public void WaitToStop()
        {
            if (_thread != null && _thread.IsAlive)
            {
                _thread.Join();
            }
        }

        protected abstract void DoWork(Object data);
    }

    class VdataGetFirstTimeWorker : Worker
    {
        public VdataGetFirstTimeWorker(WorkerManager manager, VdataCommunicator sender, ManualResetEvent signalFirstTimeDone)
            : base(null, signalFirstTimeDone)
        {
        }

        protected override void DoWork(Object data)
        {
            throw new NotImplementedException();
        }
    }

    class VdataTransactionsWorker : Worker
    {
        public VdataTransactionsWorker(WorkerManager manager,
            VdataCommunicator sender,
            ManualResetEvent waitFirstTimeDone,
            ManualResetEvent signalTransactionDone) :
            base(waitFirstTimeDone, signalTransactionDone)
        {
            
        }

        protected override void DoWork(object data)
        {
            throw new NotImplementedException();
        }


    }

    //class VdataTransactionsPutThroughWorker : Worker
    //{
    //    public VdataTransactionsPutThroughWorker(VdataWorkerManager manager, 
    //        VdataMessageSender sender, ManualResetEvent waitEndRecovery) :
    //        base(waitEndRecovery, null) {        
    //    }

    //    protected override void DoWork(object data)
    //    {
    //        IList<PriceLibrary.PriceService.StockBase> transactions;
    //        try
    //        {
    //            transactions = (IList<PriceLibrary.PriceService.StockBase>)data;
    //        }
    //        catch (InvalidCastException ex)
    //        {
    //            throw new InvalidCastException("Data must be IList<PriceLibrary.PriceService.StockBase>: " + ex.Message);
    //        }

    //        ProcessTransactionPutThrough(transactions);
    //    }

    //    private void ProcessTransactionPutThrough(IList<PriceLibrary.PriceService.StockBase> transactions)
    //    {
    //        foreach (PriceLibrary.PriceService.StockBase stockbase in transactions)
    //        {
    //            //if (_terminalEvent.WaitOne(0, false)) return;

    //            var transaction = (PriceLibrary.PriceService.Transaction)stockbase;

    //            _sender.SendTransactionPutThrough(transaction);                
    //        }             
    //    }
    //}


    /// <summary>
    /// This class do nothing but wait for some seconds
    /// </summary>
    class WorkerWaiter : Worker
    {
        public WorkerWaiter(ManualResetEvent wait, ManualResetEvent signal, int seconds)
            : base(wait, signal) 
        {
            _seconds = seconds;
        }


        protected int _seconds;
        
        protected override void DoWork(object data)
        {
            _state = WorkerState.Working;
            for (int i = 0; i < _seconds; i++)
            {
                Thread.Sleep(1000);
            }
            _state = WorkerState.Finished;
        }
    }
        
}
